package io.kiki.sba.registry.common.model.store;


import io.kiki.sba.registry.cache.Sizer;
import lombok.Getter;
import lombok.Setter;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;

@Setter
@Getter
public class DataCenterToSubDatumMap implements Serializable, Sizer {
    private static final long serialVersionUID = 1L;

    private final String dataInfoId;
    private final String instanceId;
    private final String dataId;
    private final String group;

    private final Map<String, SubDatum> dataCenterToSubDatumMap;

    public DataCenterToSubDatumMap(String dataInfoId, Map<String, SubDatum> dataCenterToSubDatumMap) {
        DataInfo dataInfo = DataInfo.valueOf(dataInfoId);
        this.dataInfoId = dataInfoId;
        this.instanceId = dataInfo.getInstanceId();
        this.dataId = dataInfo.getDataId();
        this.group = dataInfo.getGroup();

        this.dataCenterToSubDatumMap = dataCenterToSubDatumMap;
    }

    public static DataCenterToSubDatumMap intern(DataCenterToSubDatumMap dataCenterToSubDatumMap) {
        if (CollectionUtils.isEmpty(dataCenterToSubDatumMap.getDataCenterToSubDatumMap())) {
            return dataCenterToSubDatumMap;
        }
        Map<String, SubDatum> datumMap = new HashMap<>(dataCenterToSubDatumMap.getDataCenterToSubDatumMap().size());
        Set<Entry<String, SubDatum>> entrySet = dataCenterToSubDatumMap.dataCenterToSubDatumMap.entrySet();
        for (Entry<String, SubDatum> entry : entrySet) {
            if (entry.getValue() == null) {
                continue;
            }
            datumMap.put(entry.getKey(), SubDatum.intern(entry.getValue()));
        }
        return new DataCenterToSubDatumMap(StringInterner.intern(dataCenterToSubDatumMap.dataInfoId), datumMap);
    }

    public static DataCenterToSubDatumMap of(SubDatum subDatum) {
        return new DataCenterToSubDatumMap(subDatum.getDataInfoId(), Collections.singletonMap(subDatum.getDataCenter(), SubDatum.intern(subDatum)));
    }

    @Override
    public int size() {
        return CollectionUtils.isEmpty(dataCenterToSubDatumMap) ? 0 : dataCenterToSubDatumMap.values().stream().mapToInt(SubDatum::size).sum();
    }


    public Set<String> dataCenterSet() {
        if (CollectionUtils.isEmpty(dataCenterToSubDatumMap)) {
            return Collections.emptySet();
        }
        return dataCenterToSubDatumMap.keySet();
    }

    public SubDatum getSubDatum(String dataCenter) {
        if (CollectionUtils.isEmpty(dataCenterToSubDatumMap)) {
            return null;
        }
        return dataCenterToSubDatumMap.get(dataCenter);
    }

    public long getDataCenterToSubDatumVersionMap(String dataCenter) {
        if (CollectionUtils.isEmpty(dataCenterToSubDatumMap)) {
            return Long.MIN_VALUE;
        }
        SubDatum subDatum = dataCenterToSubDatumMap.get(dataCenter);
        if (subDatum == null) {
            return Long.MIN_VALUE;
        }
        return subDatum.getVersion();
    }

    public int getPubNum() {
        return CollectionUtils.isEmpty(dataCenterToSubDatumMap) ? 0 : dataCenterToSubDatumMap.values().stream().mapToInt(SubDatum::getSubPublisherListSize).sum();
    }

    public int getDataBoxBytes() {
        return CollectionUtils.isEmpty(dataCenterToSubDatumMap) ? 0 : dataCenterToSubDatumMap.values().stream().mapToInt(SubDatum::getDataBoxSizeCache).sum();
    }

    public Map getDataCenterToSubDatumVersionMap() {
        if (CollectionUtils.isEmpty(dataCenterToSubDatumMap)) {
            return Collections.EMPTY_MAP;
        }
        Map<String, Long> dataCenterToSubDatumVersionMap = new HashMap<>(dataCenterToSubDatumMap.size());
        for (Entry<String, SubDatum> entry : dataCenterToSubDatumMap.entrySet()) {
            dataCenterToSubDatumVersionMap.put(entry.getKey(), entry.getValue().getVersion());
        }
        return dataCenterToSubDatumVersionMap;
    }


    public void mustUnzipped() {
        for (SubDatum subDatum : dataCenterToSubDatumMap.values()) {
            subDatum.mustUnzipped();
        }
    }

    public List<Long> getRecentVersions(String dataCenter) {
        SubDatum subDatum = dataCenterToSubDatumMap.get(dataCenter);
        if (subDatum == null) {
            return Collections.emptyList();
        }
        return subDatum.getRecentVersionList();
    }

    public void putDatum(String dataCenter, SubDatum subDatum) {
        dataCenterToSubDatumMap.put(dataCenter, subDatum);
    }
}
